# -*- coding: utf-8 -*-
#
# The Philatelist program is a fork of the OpenNumismat program
# Copyright (c) 2011 - 2024 Vitaly Ignatov (OpenNumismat) <opennumismat@gmail.com>
# Copyright (c) 2021 - 2024 Victor Nabatov (Philatelist) <nabatov.victor@gmail.com>
#

from PySide6.QtCore import Qt, QDate, QLocale
from PySide6.QtSql import QSqlQuery
from PySide6.QtWidgets import QDialog, QTextEdit, QVBoxLayout, QDialogButtonBox

from Philatelist.Tools.DialogDecorators import storeDlgSizeDecorator


@storeDlgSizeDecorator
class SummaryDialog(QDialog):

    def __init__(self, model, parent=None):
        super().__init__(parent, Qt.WindowCloseButtonHint | Qt.WindowSystemMenuHint)
        self.setWindowTitle(self.tr("Summary"))

        buttonBox = QDialogButtonBox(Qt.Horizontal)
        buttonBox.addButton(QDialogButtonBox.Ok)
        buttonBox.accepted.connect(self.accept)

        self.textBox = QTextEdit(self)
        self.textBox.setReadOnly(True)

        layout = QVBoxLayout()
        layout.addWidget(self.textBox)
        layout.addWidget(buttonBox)
        self.setLayout(layout)

        lines_all = self.fillSummary(model)
        lines_selected = self.fillSummary(model, model.filter())
        lines = [self.tr("[Selected]")] + lines_selected + ["", self.tr("[All]")] + lines_all
        self.textBox.setText('\n'.join(lines))

    def makeSql(self, sql, filter_):
        if filter_:
            if 'WHERE' in sql:
                sql = "%s AND %s" % (sql, filter_)
            else:
                sql = "%s WHERE %s" % (sql, filter_)

        return sql

    def fillSummary(self, model, filter_=None):
        lines = []
        locale = QLocale.system()
        sql = "SELECT count(*) FROM stamps"
        sql = self.makeSql(sql, filter_)
        query = QSqlQuery(sql, model.database())
        if query.first():
            totalCount = query.record().value(0)
            lines.append(self.tr("Total count: %d") % totalCount)

        count_owned = 0
        quantity_owned = 0
        sql = "SELECT quantity FROM stamps WHERE status IN ('owned', 'ordered', 'sale', 'duplicate', 'exchange', 'variety')"
        sql = self.makeSql(sql, filter_)
        query = QSqlQuery(sql, model.database())
        while query.next():
            quantity = query.record().value('quantity')
            if not isinstance(quantity, int):
                quantity = 1

            quantity_owned += quantity
            count_owned += 1

        if count_owned == quantity_owned:
            lines.append(self.tr("Count owned: %d") % count_owned)
        else:
            lines.append(self.tr("Count owned: %d/%d") % (quantity_owned, count_owned))

        sql = "SELECT count(*) FROM stamps WHERE status='wish'"
        sql = self.makeSql(sql, filter_)
        query = QSqlQuery(sql, model.database())
        if query.first():
            count = query.record().value(0)
            lines.append(self.tr("Count wish: %d") % count)

        count_sold = 0
        sql = "SELECT count(*) FROM stamps WHERE status='sold'"
        sql = self.makeSql(sql, filter_)
        query = QSqlQuery(sql, model.database())
        if query.first():
            count_sold = query.record().value(0)
            if count_sold > 0:
                lines.append(self.tr("Count sales: %d") % count_sold)

        sql = "SELECT count(*) FROM stamps WHERE status='rarity'"
        sql = self.makeSql(sql, filter_)
        query = QSqlQuery(sql, model.database())
        if query.first():
            count = query.record().value(0)
            if count > 0:
                lines.append(self.tr("Count rarities: %d") % count)

        sql = "SELECT count(*) FROM stamps WHERE status='exchange'"
        sql = self.makeSql(sql, filter_)
        query = QSqlQuery(sql, model.database())
        if query.first():
            count = query.record().value(0)
            if count > 0:
                lines.append(self.tr("Count exchange: %d") % count)

        paid = 0
        commission = ""
        sql = "SELECT SUM(total_pay_price) FROM stamps WHERE status IN ('owned', 'ordered', 'sale', 'sold', 'exchange', 'duplicate', 'variety') AND total_pay_price<>'' AND total_pay_price IS NOT NULL"
        sql = self.makeSql(sql, filter_)
        query = QSqlQuery(sql, model.database())
        if query.first():
            paid = query.record().value(0)
            if paid:
                sql = "SELECT SUM(pay_price) FROM stamps WHERE status IN ('owned', 'ordered', 'sale', 'sold', 'exchange', 'duplicate', 'variety') AND pay_price<>'' AND pay_price IS NOT NULL"
                sql = self.makeSql(sql, filter_)
                query = QSqlQuery(sql, model.database())
                if query.first():
                    paid_without_commission = query.record().value(0)
                    if paid_without_commission:
                        commission = self.tr("(commission %d%%)") % ((paid - paid_without_commission) / paid_without_commission * 100)

                paid_str = locale.toString(float(paid), 'f', precision=2)
                lines.append(' '.join((self.tr("Paid: %s") % paid_str, commission)))
                if count_owned:
                    val = paid / count_owned
                    val_str = locale.toString(float(val), 'f', precision=2)
                    lines.append(self.tr("Average paid per item: %s") % val_str)

        earned = 0
        commission = ""
        sql = "SELECT SUM(total_sale_price) FROM stamps WHERE status='sold' AND total_sale_price<>'' AND total_sale_price IS NOT NULL"
        sql = self.makeSql(sql, filter_)
        query = QSqlQuery(sql, model.database())
        if query.first():
            earned = query.record().value(0)
            if earned:
                sql = "SELECT SUM(sale_price) FROM stamps WHERE status='sold' AND sale_price<>'' AND sale_price IS NOT NULL"
                sql = self.makeSql(sql, filter_)
                query = QSqlQuery(sql, model.database())
                if query.first():
                    earn_without_commission = query.record().value(0)
                    if earn_without_commission:
                        commission = self.tr("(commission %d%%)") % ((earn_without_commission - earned) / earn_without_commission * 100)

                earned_str = locale.toString(float(earned), 'f', precision=2)
                lines.append(' '.join((self.tr("Earned: %s") % earned_str, commission)))
                if count_sold:
                    val = earned / count_sold
                    val_str = locale.toString(float(val), 'f', precision=2)
                    lines.append(self.tr("Average earn per item: %s") % val_str)

        if paid and earned:
            total = paid - earned
            total_str = locale.toString(float(total), 'f', precision=2)
            lines.append(self.tr("Total (paid - earned): %s") % total_str)

        sql = "SELECT pay_date FROM stamps WHERE status IN ('owned', 'ordered', 'sale', 'sold', 'exchange', 'duplicate', 'variety') AND pay_date<>'' AND pay_date IS NOT NULL ORDER BY pay_date LIMIT 1"
        sql = self.makeSql(sql, filter_)
        query = QSqlQuery(sql, model.database())
        if query.first():
            date = QDate.fromString(query.record().value(0), Qt.ISODate)
            pay_date = locale.toString(date, QLocale.ShortFormat)
            lines.append(self.tr("First purchase: %s") % pay_date)

        sql = "SELECT UPPER(grade), price1, price2, price3, price4, price5, price6 quantity FROM stamps WHERE status IN ('owned', 'ordered', 'sale', 'duplicate', 'variety' AND (ifnull(price1,'')<>'' OR ifnull(price2,'')<>'' OR ifnull(price3,'')<>'' OR ifnull(price4,'')<>'' OR ifnull(price5,'')<>'' OR ifnull(price6,'')<>'')"
        sql = self.makeSql(sql, filter_)
        query = QSqlQuery(sql, model.database())
        est_owned = 0
        count = 0
        stamps_quantity = 0
        comment = ""
        while query.next():
            record = query.record()
            grade = record.value(0)
            price1 = record.value(1)
            price2 = record.value(2)
            price3 = record.value(3)
            price4 = record.value(4)
            quantity = int(record.value(5) or 1)
            try:
                if grade[:2] in ('XF'):
                    price = price4 if price4 else price3 * 1.6 if price3 else price2 * 2.2 if price2 else price1 * 5.5 if price1 else 0

                elif grade[:2] in ('VF'):
                    price = price3 if price3 else price4 * 0.6 if price4 else price2 * 1.4 if price2 else price1 * 3.5 if price1 else 0

                elif grade[:2] in ('F',):
                    priceU = price4 if price4 else price3 * 1.6 if price3 else price2 * 2.2 if price2 else price1 * 5.5 if price1 else 0
                    priceX = price3 if price3 else price4 * 0.6 if price4 else price2 * 1.4 if price2 else price1 * 3.5 if price1 else 0
                    price = priceX + (priceU - priceX) * 0.6

                elif grade[:2] in ('VF',):
                    price = price2 if price2 else price3 * 0.7 if price3 else price4 * 0.45 if price4 else price1 * 2.5 if price1 else 0

                elif grade[:2] in ('G/VG'):
                    price = price1 if price1 else price2 * 0.4 if price2 else price3 * 0.3 if price3 else price4 * 0.18 if price4 else 0

                elif grade[:2] in ('B',):
                    price = price1 * 0.5 if price1 else price2 * 0.2 if price2 else price3 * 0.14 if price3 else price4 * 0.09 if price4 else 0
                else:
                    price = price4 if price4 else price3 if price3 else price2 if price2 else price1 if price1 else 0

                if price:
                    est_owned += price * quantity
                    count += 1
                    stamps_quantity += quantity

            except TypeError:
                continue

        if count:
            if count == stamps_quantity:
                comment = self.tr("(calculated for %d stamps)") % count
            else:
                comment = self.tr("(calculated for %d/%d stamps)") % (stamps_quantity, count)

        lines.append(' '.join((self.tr("Estimation owned: %d") % est_owned, comment)))

        sql = "SELECT price1, price2, price3, price4, price5, price6 FROM stamps WHERE status='wish' AND (ifnull(price1,'')<>'' OR ifnull(price2,'')<>'' OR ifnull(price3,'')<>'' OR ifnull(price4,'')<>'' OR ifnull(price5,'')<>'' OR ifnull(price6,'')<>'')"
        sql = self.makeSql(sql, filter_)
        query = QSqlQuery(sql, model.database())
        est_wish = 0
        count = 0
        comment = ""
        while query.next():
            record = query.record()
            price1 = record.value(0)
            price2 = record.value(1)
            price3 = record.value(2)
            price4 = record.value(3)
            price = price4 if price4 else price3 if price3 else price2 if price2 else price1 if price1 else 0
            try:
                if price:
                    est_wish += price
                    count += 1

            except TypeError:
                continue

        if count:
            comment = self.tr("(calculated for %d stamps)") % count

        lines.append(' '.join((self.tr("Estimation wish: %d") % est_wish, comment)))

        sql = "SELECT count(*) FROM images"
        sql = self.makeSql(sql, filter_)
        query = QSqlQuery(sql, model.database())
        if query.first():
            count = query.record().value(0)
            lines.append(self.tr("Count images: %d") % count)

        return lines

    def materialFilter(self, *materials):
        filters = []
        for material in materials:
            for material_variant in (material.lower(), material.upper(), material.capitalize()):
                filters.append("'%s'" % material_variant)

        return 'material IN (%s)' % ','.join(filters)

    def materialCount(self, materials, model, filter_):
        material_count = 0
        material_quantity = 0
        material_filter = self.materialFilter(*materials)
        sql = "SELECT quantity FROM stamps WHERE status IN ('owned', 'ordered', 'sale', 'duplicate', 'exchange') AND %s" % material_filter
        sql = self.makeSql(sql, filter_)
        query = QSqlQuery(sql, model.database())
        while query.next():
            record = query.record()
            quantity = int(record.value('quantity') or 1)
            material_count += 1
            material_quantity += quantity

        return material_count, material_quantity
